<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者，助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件，未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types=1);

namespace app\services\activity\score;

use app\dao\activity\score\StoreScoreDao;
use app\services\activity\coupon\StoreCouponServices;
use app\services\activity\integral\StoreIntegralOrderServices;
use app\jobs\ProductCopyJob;
use app\Request;
use app\services\BaseServices;
use app\services\product\product\CopyTaobaoServices;
use app\services\product\product\StoreCategoryServices;
use app\services\product\product\StoreDescriptionServices;
use app\services\product\product\StoreProductCateServices;
use app\services\product\product\StoreProductCouponServices;
use app\services\product\product\StoreProductServices;
use app\services\product\product\StoreVisitServices;
use app\services\product\sku\StoreProductAttrResultServices;
use app\services\product\sku\StoreProductAttrServices;
use app\services\product\sku\StoreProductAttrValueServices;
use app\jobs\ProductLogJob;
use crmeb\exceptions\AdminException;
use crmeb\exceptions\ApiException;
use crmeb\services\CacheService;

/**
 *
 * Class StoreIntegralServices
 * @package app\services\activity
 * @method getOne(array $where, ?string $field = '*', array $with = []) 根据条件获取一条数据
 * @method get(int $id, ?array $field) 获取一条数据
 */
class StoreScoreServices extends BaseServices
{
    const THODLCEG = 'ykGUKB';

    /**
     * StoreIntegralServices constructor.
     * @param StoreScoreDao $dao
     */
    public function __construct(StoreScoreDao $dao)
    {
        $this->dao = $dao;
    }

    /**
     * 获取指定条件下的条数
     * @param array $where
     */
    public function getCount(array $where)
    {
        $this->dao->count($where);
    }

    /**
     * 新增编辑商品
     * @param int $id
     * @param array $data
     */
    public function save(int $id, array $data)
    {
        if (!$data['name']) throw new AdminException(400338);

        $detail = $data['attrs'];
        $attr = $data['items'];
        $type = $data['type'];

        if($detail){
            $data['price'] = min(array_column($detail, 'price'));
        }

        $data['cate_id'] = "";
        $data['label_id'] = "";
        if($type == 1){
            $data['stock'] = $data['stock_type'] == 1 ? 999999 : $data['stock'];
        }else{
            $data['stock'] = array_sum(array_column($detail, 'stock'));
        }

        unset($data['description'], $data['coupon_ids'], $data['items'], $data['attrs']);
        /** @var StoreProductAttrServices $storeProductAttrServices */
        $storeProductAttrServices = app()->make(StoreProductAttrServices::class);
        /** @var StoreCouponServices $storeCouponServices */
        $storeCouponServices = app()->make(StoreCouponServices::class);

        $this->transaction(function () use ($id, $data, $storeProductAttrServices, $storeCouponServices, $detail, $attr, $type) {
            $coupon = [];
            if ($type == 1) {
                $coupon['title'] = $data['name']; // 标题
                $coupon['total_count'] = $data['stock']; // 总数
                $coupon['is_use_all_product'] = intval($data['coupon_type']);//1通用 0部分商品; // 是否适应所有商品
                $coupon['has_use_limit'] = 0; // 是否存在门槛
                $coupon['use_min_price'] = $data['use_min_price']; // 允许使用的最小金额
                $coupon['price'] = $data['worth']; // 优惠劵价格
                $coupon['start_time'] = time(); // 优惠劵生效开始时间
                $coupon['end_time'] = 1; // 优惠劵失效结束时间
                $coupon['use_day'] = 365; // 领取后多少天可以使用
                $coupon['available_type'] = 2; // 有效期类型(1. 时间范围, 2. 天数)
                $coupon['has_get_limit'] = 2; // 领取限制(1. 有限制, 0. 不存在限制)
                $coupon['get_max_count'] = 999; // 限制领取次数
                $coupon['products'] = $data['products']; // 适用商品
                $coupon['create_type'] = 2;//积分商品来源
                $coupon['status'] = 1;//上下架状态 1上架, 0下架

                $detail = [];
                $detail[0]["price"] = $data['price'];
                $detail[0]["cost"] = $data['price'];
                $detail[0]["stock"] = $data['stock'] == 0 ? 99999999 : $data['stock'];
                $detail[0]["pic"] = $data['image'];
                $detail[0]["ot_price"] = $data['price'];
            }

            if ($type == 1) {
                $attr = [
                    [
                        'value' => '规格',
                        'detailValue' => '',
                        'attrHidden' => '',
                        'detail' => ['默认']
                    ]
                ];
                $detail[0]['value1'] = '规格';
                $detail[0]['detail'] = ['规格' => '默认'];
                $detail[0]['is_virtual'] = $type;
            }
            foreach ($detail as &$item) {
                $item['is_virtual'] = $data['type'];
            }
            if ($id) {
                $oldInfo = $this->get($id)->toArray();
                if ($oldInfo['type'] != $type) {
                    throw new AdminException(400573);
                }

                unset($data['sales']);
                $this->dao->update($id, $data);

                $skuList = $this->validateProductAttr($attr, $detail, $id, 5);
                $attrRes = $storeProductAttrServices->saveProductAttr($skuList, $id, 5, 0, $type);
                if (!$attrRes) throw new AdminException(100022);

                if ($type == 1) {
                    $couponRes = $storeCouponServices->save($oldInfo['coupon_id'],$coupon);
                    if (!$couponRes) throw new AdminException(100022);
                }
            } else {
                $data['add_time'] = time();

                $couponRes = 0;
                if ($type == 1) {
                    $couponRes = $storeCouponServices->save(0, $coupon);
                    if (!$couponRes) throw new AdminException(100022);
                }
                $data['coupon_id'] = $couponRes;
                $res = $this->dao->save($data);
                $skuList = $this->validateProductAttr($attr, $detail, $res->id, 5);
                $attrRes = $storeProductAttrServices->saveProductAttr($skuList, $res->id, 5, 0, $type);
                if (!$attrRes) throw new AdminException(100022);
            }
        });
    }

    /**
     * 积分商品添加
     * @param int $id
     * @param array $data
     */
    public function saveData(int $id, array $data)
    {
        if ($data['images']) {
            $data['images'] = json_encode($data['images']);
        }
        if ($id) {
            $res = $this->dao->update($id, $data);
            if (!$res) throw new AdminException(100007);
        } else {
            $res = $this->dao->save($data);
            if (!$res) throw new AdminException(100022);
        }
    }

    /**
     * 批量添加商品
     * @param array $data
     */
    public function saveBatchData(array $data)
    {
        foreach ($data as $k => $v) {
            $product = $v;
            if ($product['images']) {
                $product['images'] = json_encode($product['images']);
            }
            $product['is_show'] = $v['is_show'] ?? 0;
            $product['is_host'] = $v['is_host'] ?? 0;
            $product['sort'] = $v['sort'] ?? 0;
            $this->saveData(0, $product);
        }
        return true;
    }

    /**
     * 积分商品列表
     * @param array $where
     * @return array
     */
    public function systemPage(array $where)
    {
        [$page, $limit] = $this->getPageValue();
        $list = $this->dao->getList($where, $page, $limit);
        $count = $this->dao->count($where);
        return compact('list', 'count');
    }

    /**
     * 获取详情
     * @param int $id
     * @return array|\think\Model|null
     */
    public function getInfo(int $id, string $from = "")
    {
        $info = $this->dao->get($id);
        if (!$info) {
            throw new AdminException(400533);
        }
        if ($info->is_del) {
            throw new AdminException(400534);
        }
        $info['price'] = floatval($info['price']);
        /** @var StoreDescriptionServices $storeDescriptionServices */
        $storeDescriptionServices = app()->make(StoreDescriptionServices::class);
        $info['description'] = $storeDescriptionServices->getDescription(['product_id' => $id, 'type' => 5]);
        $attrs = $this->attrList($id, $id);

        if($from == "api"){
            unset($attrs['header']);
        }
        if($info->type == 1){
            /** @var StoreCouponServices $storeCouponServices */
            $storeCouponServices = app()->make(StoreCouponServices::class);
            $coupon = $storeCouponServices->detail($info->coupon_id);
            if($coupon == [] || !isset($coupon['products'])){
                throw new AdminException("错误的虚拟商品可用商品信息");
            }
            $info['products'] = $coupon['products'];
        }

        $info['attrs'] = $attrs;
        return $info;
    }

    /**
     * 获取规格
     * @param int $id
     * @param int $pid
     * @return mixed
     */
    public function attrList(int $id)
    {
        /** @var StoreProductAttrResultServices $storeProductAttrResultServices */
        $storeProductAttrResultServices = app()->make(StoreProductAttrResultServices::class);
        $combinationResult = $storeProductAttrResultServices->value(['product_id' => $id, 'type' => 5], 'result');
        $items = json_decode($combinationResult, true)['attr'];
        $productAttr = $this->getAttr($items, $id, 5);
        $combinationAttr = $this->getAttr($items, $id, 5);
        foreach ($productAttr as $pk => $pv) {
            foreach ($combinationAttr as &$sv) {
                if ($pv['detail'] == $sv['detail']) {
                    $productAttr[$pk] = $sv;
                }
            }
            $productAttr[$pk]['detail'] = json_decode($productAttr[$pk]['detail']);
        }
        $attrs['items'] = $items;
        $attrs['value'] = $productAttr;
        foreach ($items as $key => $item) {
            $header[] = ['title' => $item['value'], 'key' => 'value' . ($key + 1), 'align' => 'center', 'minWidth' => 80];
        }
        $header[] = ['title' => '图片', 'slot' => 'pic', 'align' => 'center', 'minWidth' => 120];
        $header[] = ['title' => '价值', 'slot' => 'cost', 'align' => 'center', 'minWidth' => 120];
        $header[] = ['title' => '抵扣积分', 'key' => 'price', 'type' => 1, 'align' => 'center', 'minWidth' => 80];
        $header[] = ['title' => '库存', 'key' => 'stock', 'align' => 'center', 'minWidth' => 80];
        $header[] = ['title' => '兑换次数', 'key' => 'quota', 'type' => 1, 'align' => 'center', 'minWidth' => 80];
        $header[] = ['title' => '重量(KG)', 'key' => 'weight', 'align' => 'center', 'minWidth' => 80];
        $header[] = ['title' => '体积(m³)', 'key' => 'volume', 'align' => 'center', 'minWidth' => 80];
        $header[] = ['title' => '条形码', 'key' => 'code', 'align' => 'center', 'minWidth' => 80];
        $attrs['header'] = $header;
//        dd($attrs);
        return $attrs;
    }

    /**
     * 获得规格
     * @param $attr
     * @param $id
     * @param $type
     * @return array
     */
    public function getAttr($attr, $id, $type)
    {
        /** @var StoreProductAttrValueServices $storeProductAttrValueServices */
        $storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
        list($value, $head) = attr_format($attr);
        $valueNew = [];
        $count = 0;
        foreach ($value as $suk) {
            $detail = explode(',', $suk);
            $sukValue = $storeProductAttrValueServices->getColumn(['product_id' => $id, 'type' => $type, 'suk' => $suk], 'bar_code,cost,price,ot_price,stock,unique,image as pic,weight,volume,brokerage,brokerage_two,quota,quota_show', 'suk');
            if (count($sukValue)) {
                foreach ($detail as $k => $v) {
                    $valueNew[$count]['value' . ($k + 1)] = $v;
                }
                $valueNew[$count]['detail'] = json_encode(array_combine($head, $detail));
                $valueNew[$count]['pic'] = $sukValue[$suk]['pic'] ?? '';
                $valueNew[$count]['price'] = $sukValue[$suk]['price'] ? floatval($sukValue[$suk]['price']) : 0;
                $valueNew[$count]['cost'] = $sukValue[$suk]['cost'] ? floatval($sukValue[$suk]['cost']) : 0;
//                $valueNew[$count]['ot_price'] = isset($sukValue[$suk]['ot_price']) ? floatval($sukValue[$suk]['ot_price']) : 0;
                $valueNew[$count]['stock'] = $sukValue[$suk]['stock'] ? intval($sukValue[$suk]['stock']) : 0;
//                $valueNew[$count]['quota'] = $sukValue[$suk]['quota'] ? intval($sukValue[$suk]['quota']) : 0;
                $valueNew[$count]['quota'] = isset($sukValue[$suk]['quota_show']) && $sukValue[$suk]['quota_show'] ? intval($sukValue[$suk]['quota_show']) : 0;
                $valueNew[$count]['code'] = $sukValue[$suk]['bar_code'] ?? '';
                $valueNew[$count]['weight'] = $sukValue[$suk]['weight'] ? floatval($sukValue[$suk]['weight']) : 0;
                $valueNew[$count]['volume'] = $sukValue[$suk]['volume'] ? floatval($sukValue[$suk]['volume']) : 0;
                $valueNew[$count]['unique'] = $sukValue[$suk]['unique'] ?? '';
//                $valueNew[$count]['brokerage'] = $sukValue[$suk]['brokerage'] ? floatval($sukValue[$suk]['brokerage']) : 0;
//                $valueNew[$count]['brokerage_two'] = $sukValue[$suk]['brokerage_two'] ? floatval($sukValue[$suk]['brokerage_two']) : 0;
                $valueNew[$count]['_checked'] = $type != 0;
                $count++;
            }
        }
        return $valueNew;
    }

    /**
     * 积分商品详情
     * @param Request $request
     * @param int $id
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function scoreDetail(Request $request, int $id)
    {
        $storeInfo = $this->dao->getOne(['id' => $id], '*', ['getPrice']);
        if (!$storeInfo) {
            throw new AdminException(400533);
        } else {
            $storeInfo = $storeInfo->toArray();
        }
        $siteUrl = sys_config('site_url');
        $storeInfo['image'] = set_file_url($storeInfo['image'], $siteUrl);
        $storeInfo['image_base'] = set_file_url($storeInfo['image'], $siteUrl);
        $storeInfo['product_price'] = (int)$storeInfo['product_price'];
        $storeInfo['sale_stock'] = 0;
        if ($storeInfo['stock'] > 0) $storeInfo['sale_stock'] = 1;
        $uid = $request->uid();
        /** @var StoreDescriptionServices $storeDescriptionService */
        $storeDescriptionService = app()->make(StoreDescriptionServices::class);
        $storeInfo['description'] = $storeDescriptionService->getDescription(['product_id' => $id, 'type' => 5]);
        $data['storeInfo'] = get_thumb_water($storeInfo, 'big', ['image', 'images']);
        $storeInfoNew = get_thumb_water($storeInfo, 'small');
        $data['storeInfo']['small_image'] = $storeInfoNew['image'];

        /** @var StoreProductAttrServices $storeProductAttrServices */
        $storeProductAttrServices = app()->make(StoreProductAttrServices::class);
        list($productAttr, $productValue) = $storeProductAttrServices->getProductAttrDetail($id, $uid, 0, 5, $id);
        foreach ($productValue as &$item) {
            $item['cost'] = (int)$item['cost'];
            $item['ot_price'] = (int)$item['ot_price'];
            $item['price'] = (int)$item['price'];
            $item['vip_price'] = (int)$item['vip_price'];
        }
        $data['productAttr'] = $productAttr;
        $data['productValue'] = $productValue;
        /** @var StoreVisitServices $storeVisit */
        $storeVisit = app()->make(StoreVisitServices::class);
        $storeVisit->setView($uid, $id, 'combination', $id, 'view');
        $data['routine_contact_type'] = sys_config('routine_contact_type', 0);
        //浏览记录
        ProductLogJob::dispatch(['visit', ['uid' => $uid, 'product_id' => $id]]);
        return $data;
    }

    /**
     * 修改销量和库存
     * @param $num
     * @param $integralId
     * @return bool
     */
    public function decIntegralStock(int $num, int $integralId, string $unique)
    {
        if ($unique) {
            /** @var StoreProductAttrValueServices $skuValueServices */
            $skuValueServices = app()->make(StoreProductAttrValueServices::class);
            //减去积分商品的sku库存增加销量
            $res = false !== $skuValueServices->decProductAttrStock($integralId, $unique, $num, 5);
            //减去积分商品库存
            $res = $res && $this->dao->decStockIncSales(['id' => $integralId], $num);
            //获取拼团的sku
            $sku = $skuValueServices->value(['product_id' => $integralId, 'unique' => $unique, 'type' => 5], 'suk');
            //减去当前普通商品sku的库存增加销量
            $res = $res && $skuValueServices->decStockIncSales(['product_id' => $integralId, 'suk' => $sku, 'type' => 5], $num);
        } else {
            $res = false !== $this->dao->decStockIncSales(['id' => $integralId], $num);
        }
//        /** @var StoreProductServices $services */
//        $services = app()->make(StoreProductServices::class);
//        //减去普通商品库存
//        $res = $res && $services->decProductStock($num, $integralId);
        return $res;
    }

    /**
     * 获取一条积分商品
     * @param $id
     * @return mixed
     */
    public function getScoreOne($id)
    {
        return $this->dao->validProduct($id, '*');
    }

    /**
     * 验证积分商品下单库存限量
     * @param int $uid
     * @param int $integralId
     * @param int $num
     * @param string $unique
     * @return string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function checkoutProductStock(int $uid, int $integralId, int $num = 1, string $unique = '')
    {
        /** @var StoreProductAttrValueServices $attrValueServices */
        $attrValueServices = app()->make(StoreProductAttrValueServices::class);
        if ($unique == '') {
            $unique = $attrValueServices->value(['product_id' => $integralId, 'type' => 5], 'unique');
        }
        $StoreScoreInfo = $this->getScoreOne($integralId);
        if (!$StoreScoreInfo) {
            throw new ApiException(400093);
        }

//        /** @var StoreIntegralOrderServices $orderServices */         限购相关
//        $orderServices = app()->make(StoreIntegralOrderServices::class);
//        $userBuyCount = $orderServices->getBuyCount($uid, $integralId);
//        if ($StoreScoreInfo['once_num'] < $num && $StoreScoreInfo['once_num'] != -1) {
//            throw new ApiException(410313, ['num' => $StoreScoreInfo['once_num']]);
//        }
//        if ($StoreScoreInfo['num'] < ($userBuyCount + $num) && $StoreScoreInfo['num'] != -1) {
//            throw new ApiException(410298, ['num' => $StoreScoreInfo['num']]);
//        }
        $res = $attrValueServices->getOne(['product_id' => $integralId, 'unique' => $unique, 'type' => 5]);
//        if ($num > $res['quota']) {
//            throw new ApiException(410297, ['num' => $num]);
//        }
        $product_stock = $attrValueServices->value(['product_id' => $StoreScoreInfo['id'], 'suk' => $res['suk'], 'type' => 5], 'stock');
        if ($product_stock < $num) {
            throw new ApiException(410297, ['num' => $num]);
        }
        return $unique;
    }

    /**
     * 获取推荐积分商品
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getScoreList(array $where)
    {
        [$page, $limit] = $this->getPageValue();
        if($where['type'] == ''){
            unset($where['type']);
        }
        $list = $this->dao->getList($where, $page, $limit, 'id,image,name,price,worth,sales,type');
        return $list;
    }

    /**
     * 添加商品属性数据判断
     * @param array $attrList
     * @param array $valueList
     * @param int $productId
     * @param int $type
     * @param int $validate
     * @return array
     */
    public function validateProductAttr(array $attrList, array $valueList, int $productId, $type = 0, int $validate = 1)
    {
        $result = ['attr' => $attrList, 'value' => $valueList];
        $attrValueList = [];
        $attrNameList = [];
        foreach ($attrList as $index => $attr) {
            if (!isset($attr['value'])) {
                throw new AdminException(400574);
            }
            $attr['value'] = trim($attr['value']);
            if (!isset($attr['value'])) {
                throw new AdminException(400574);
            }
            if (!isset($attr['detail']) || !count($attr['detail'])) {
                throw new AdminException(400575);
            }
            foreach ($attr['detail'] as $k => $attrValue) {
                $attrValue = trim($attrValue);
                if (empty($attrValue)) {
                    throw new AdminException(400576);
                }
                $attr['detail'][$k] = $attrValue;
                $attrValueList[] = $attrValue;
                $attr['detail'][$k] = $attrValue;
            }
            $attrNameList[] = $attr['value'];
            $attrList[$index] = $attr;
        }
        $attrCount = count($attrList);
        foreach ($valueList as $index => $value) {
            if (!isset($value['detail']) || count($value['detail']) != $attrCount) {
                throw new AdminException(400577);
            }
            if (!isset($value['price']) || !is_numeric($value['price']) || floatval($value['price']) != $value['price']) {
                throw new AdminException(400578);
            }
            if ($validate && (!isset($value['stock']) || !is_numeric($value['stock']) || intval($value['stock']) != $value['stock'])) {
                throw new AdminException(4005792);
            }
//            if (!isset($value['cost']) || !is_numeric($value['cost']) || floatval($value['cost']) != $value['cost']) {
//                throw new AdminException(400580);
//            }
//            if ($validate && (!isset($value['pic']) || empty($value['pic']))) {
//                throw new AdminException(400581);
//            }
            foreach ($value['detail'] as $attrName => $attrValue) {
                //如果attrName 存在空格 则这个规格key 会出现两次
                unset($valueList[$index]['detail'][$attrName]);
                $attrName = trim($attrName);
                $attrValue = trim($attrValue);
                if (!in_array($attrName, $attrNameList, true)) {
                    throw new AdminException(400582, ['name' => $attrName]);
                }
                if (!in_array($attrValue, $attrValueList, true)) {
                    throw new AdminException(400583, ['name' => $attrValue]);
                }
                if (empty($attrName)) {
                    throw new AdminException(400576);
                }
                $valueList[$index]['detail'][$attrName] = $attrValue;
            }
        }
        $attrGroup = [];
        $valueGroup = [];
        foreach ($attrList as $k => $value) {
            $attrGroup[] = [
                'product_id' => $productId,
                'attr_name' => $value['value'],
                'attr_values' => $value['detail'],
                'type' => $type
            ];
        }
        /** @var StoreProductAttrValueServices $storeProductAttrValueServices */
        $storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
        $skuArray = $storeProductAttrValueServices->getColumn(['product_id' => $productId, 'type' => $type], 'unique', 'suk');
        foreach ($valueList as $k => $value) {
            $sku = implode(',', $value['detail']);
            $skuValue = [
                'product_id' => $productId,
                'suk' => $sku,
                'price' => $value['price'],
                'cost' => $value['cost'] ?? 0,
                'ot_price' => $value['price'],
                'unique' => $skuArray[$sku] ?? '',
                'image' => $value['pic'],
                'bar_code' => $value['code'] ?? '',
                'weight' => $value['weight'] ?? 0,
                'volume' => $value['volume'] ?? 0,
                'brokerage' => $value['brokerage'] ?? 0,
                'brokerage_two' => $value['brokerage_two'] ?? 0,
                'type' => $type,
                'quota' => $value['quota'] ?? 0,
                'quota_show' => $value['quota'] ?? 0,
                'vip_price' => $value['vip_price'] ?? 0,
                'is_virtual' => $value['is_virtual'] ?? 0,
                'coupon_id' => $value['coupon_id'] ?? 0,
                'virtual_list' => $value['virtual_list'] ?? [],
                'disk_info' => $value['disk_info'] ?? '',
            ];

            if ($validate) {
                $skuValue['stock'] = $value['stock'];
            }
            $valueGroup[$sku] = $skuValue;
        }

        if (!count($attrGroup) || !count($valueGroup)) {
            throw new AdminException(400584);
        }
        return compact('result', 'attrGroup', 'valueGroup');
    }
}
